package lk.icta.common.web;

import lk.icta.common.AppConstants;
import lk.icta.common.dao.DistrictDAO;
import lk.icta.common.dao.RailwayTrackDAO;
import lk.icta.common.entity.District;
import lk.icta.common.entity.RailwayTrack;
import lk.icta.core.dto.LeaseArrearsDetails;
import lk.icta.core.entity.AlienationRailway;
import lk.icta.core.service.AlienationRailwayManagementService;
import lk.icta.core.service.LandRailwayManagementService;
import lk.icta.core.service.RailwayPaymentManagementService;
import lk.icta.user.entity.User;
import org.codehaus.jackson.map.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * @author Supun Viraj Rathnayaka
 */
public class JSONRailwayReportService extends HttpServlet {

    private static final Logger logger = LoggerFactory.getLogger(JSONRailwayLandLookupService.class);
    private final ObjectMapper mapper = new ObjectMapper();
    private RailwayTrackDAO railwayTrackDAO;
    private DistrictDAO districtDAO;
    private RailwayPaymentManagementService railwayPaymentManagementService;
    private AlienationRailwayManagementService alienationRailwayManagementService;
    private LandRailwayManagementService landRailwayManagementService;

    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(config.getServletContext());
        railwayTrackDAO = (RailwayTrackDAO) context.getBean("railwayTrackDAO");
        districtDAO = (DistrictDAO) context.getBean("districtDAO");
        railwayPaymentManagementService = (RailwayPaymentManagementService) context.getBean("railwayPaymentManagementService");
        alienationRailwayManagementService = (AlienationRailwayManagementService) context.getBean("alienationRailwayManagementService");
        landRailwayManagementService = (LandRailwayManagementService) context.getBean("landRailwayManagementService");
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String type = request.getParameter(WebConstants.TYPE);
        HashMap<String, Object> optionLists = new HashMap<String, Object>();
        try {
            HttpSession session = request.getSession();
            User user = (User) session.getAttribute(AppConstants.SESSION_USER_BEAN);
            Locale locale = (Locale) session.getAttribute(WebConstants.SESSION_USER_LANG);
            String language = locale.getLanguage();
            int trackId = Integer.parseInt(request.getParameter("track"));
            int districtId = Integer.parseInt(request.getParameter("district"));
            if(type.equals("IncomeReport")){
                int year = Integer.parseInt(request.getParameter("year"));
                int reportMode = Integer.parseInt(request.getParameter("mode"));

                List<Map<String, Date>> timeFrames = null;

                switch (reportMode){
                    case 0: // Annual Report
                        timeFrames = getTimeFrameList(year, 1);
                        break;
                    case 1: // Semi Annual Report
                        timeFrames = getTimeFrameList(year, 2);

                        break;
                    case 2: // Quarter Report
                        timeFrames = getTimeFrameList(year, 4);
                        break;
                    case 3: // Monthly Report
                        timeFrames = getTimeFrameList(year, 12);
                        break;
                }
                optionLists.put("IncomeData", getReport(timeFrames, trackId, districtId, language));
            }else if(type.equals("LeaseStat")){
                int branchId = Integer.parseInt(request.getParameter("branch"));
                double fromValue;
                double toValue;
                try{
                    fromValue = Double.parseDouble(request.getParameter("valFrom"));
                }catch (NumberFormatException e){
                    fromValue = 0d;
                }
                try{
                    toValue = Double.parseDouble(request.getParameter("valTo"));
                }catch (NumberFormatException e){
                    toValue = 0d;
                }
                String fromDate = request.getParameter("dtFrom");
                String toDate = request.getParameter("dtTo");

                optionLists.put("leaseList", alienationRailwayManagementService.AlienationStatisticsReportData(branchId, trackId, districtId, fromDate, toDate, fromValue, toValue, user, language));

            }else if(type.equals("LandStat")){
                int branchId = Integer.parseInt(request.getParameter("branch"));

                Date toDate, fromDate;
                int lStateId = Integer.parseInt(request.getParameter("landSt"));

                try {
                    fromDate = new Date(Long.parseLong(request.getParameter("dtFrom")));
                    toDate = new Date(Long.parseLong(request.getParameter("dtTo")));
                } catch (NumberFormatException e) {
                    fromDate = null;
                    toDate = null;
                }

                optionLists.put("landList", landRailwayManagementService.getLandStatisticsReportData(branchId, trackId, districtId, fromDate, toDate, lStateId));

            }else if(type.equals("arrearsList")){
                int branchId = Integer.parseInt(request.getParameter("branch"));
                long minAmnt = 0;
                long maxAmnt = 0;

                try{
                    minAmnt = Long.parseLong(request.getParameter("minAmnt"));;
                }catch (Exception e){
                    logger.warn("Invalid Amount Range Parameters");
                }

                try{
                    maxAmnt = Long.parseLong(request.getParameter("maxAmnt"));
                }catch (Exception e){
                    logger.warn("Invalid Amount Range Parameters");
                }

                optionLists.put("arrearsList", populateLeaseArrearsDetails(alienationRailwayManagementService.getArrearsStatisticsReportData(branchId, trackId, districtId, minAmnt, maxAmnt)));

            }else if(type.equals("arrearsList")){
                int branchId = Integer.parseInt(request.getParameter("branch"));
                int years =  Integer.parseInt(request.getParameter("years"));

              //optionLists.put("arrearsList", populateLeaseArrearsDetails(alienationRailwayManagementService.getArrearsHistoryDetails(branchId, trackId, districtId, years)));

            }

        }catch (Exception e) {
            logger.error("Fatal Error : {}", e);
            return;
        }
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        PrintWriter out = response.getWriter();
        try {
            mapper.writeValue(out, optionLists);
            out.flush();
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
    }

    private List<LeaseArrearsDetails> populateLeaseArrearsDetails(List<AlienationRailway> arrearsStatisticsReportData) {
        List<LeaseArrearsDetails> al = new ArrayList<LeaseArrearsDetails>();
        LeaseArrearsDetails ld;
        for (AlienationRailway a : arrearsStatisticsReportData){
            ld = new LeaseArrearsDetails();
            ld.setLand_id(a.getLand().getId());
            ld.setFileNo(a.getLand().getLandFileNumber());
            ld.setReferenceNo(a.getReferenceNo());
            ld.setValuationAmount(a.getValuation().getValuationAmount());
            ld.setAnnualRental(a.getLeaseDetail().getAnnualRental());
            ld.setTotalPayable(a.getLeaseDetail().getTotalPayable());
            ld.setTotalPaid(a.getLeaseDetail().getPaidAmount());
            ld.setTotalPaidTax(a.getLeaseDetail().getPaidTax());
            ld.setArrearsAmount(a.getLeaseDetail().getArrearsAmount());
            ld.setArrearsTax(a.getLeaseDetail().getArrearsTax());
            al.add(ld);
        }
        return al;
    }

    private List<Map<String, List<Object>>> getReport(List<Map<String, Date>> timeFrames, int trackId, int districtId, String language) {
        RailwayTrack railwayTrack = null;
        List<District> districtList = null;
        if(trackId>0){
            railwayTrack = railwayTrackDAO.getRailwayTrackById(trackId);
            if(districtId > 0){
                   districtList = new ArrayList<District>();
                   districtList.add(districtDAO.getDistrictById(districtId));
            }else {
                   districtList = railwayTrack.getDistrict();
            }
        }else{
            districtList  = districtDAO.getAllDistricts();
        }

        return railwayPaymentManagementService.getTimelyIncomeReportData(timeFrames, districtList, railwayTrack, language);

    }

    private List<Map<String, Date>> getTimeFrameList(int year, int quartile) {
        SimpleDateFormat dateFormat = new SimpleDateFormat(AppConstants.DATE_FORMAT, Locale.ENGLISH);
        List<Map<String, Date>> timeFrames = new ArrayList<Map<String, Date>>();
        Map<String, Date> timeFrame;
        int sMonth = 1;
        int eMonth = (12/quartile)+1;
        int sYear = year;
        int eYear = year;
        for(int i = 0; i<quartile; i++){
            timeFrame = new HashMap<String, Date>();
            if(eMonth > 12){ eMonth = 1; eYear++; }
            try {
                timeFrame.put("startDate", dateFormat.parse("01/"+sMonth+"/"+sYear));
                timeFrame.put("endDate", dateFormat.parse("01/"+eMonth+"/"+eYear));
            } catch (ParseException e) {
                logger.error("Error in parsing time report time frame");
            }
            timeFrames.add(timeFrame);
            sMonth += 12/quartile;
            eMonth += 12/quartile;
        }
        return timeFrames;
    }
}

